package com.zyg.demo.control;

import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.RectF;
import android.os.SystemClock;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;
import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;

import com.chad.library.adapter.base.BaseItemDraggableAdapter;
import com.chad.library.adapter.base.callback.ItemDragAndSwipeCallback;
import com.zyg.demo.listener.DragListener;

/**
 * 粘合器
 *
 * @author zhengyunguang
 * created at 2019-07-24 10:06
 */
@SuppressLint("ViewConstructor")
public class GlueLayout extends FrameLayout {

    /**
     * 初始状态
     */
    private static final int GLUE_STATE_IDEL = 0;
    /**
     * 与subRecycler的item粘在一起
     */
    private static final int GLUE_STATE_WITH_SUB = 2;
    /**
     * 与parentRecycler的item粘在一起
     */
    private static final int GLUE_STATE_WITH_PARENT = 3;
    /**
     * 与parentRecycler的item粘在一起
     */
    private static final int GLUE_STATE_OUTER_RELEASE = 4;

    /**
     * subRecycler
     */
    RecyclerView subRecycler;

    /**
     * parentRecycler
     */
    RecyclerView parentRecycler;

    /**
     * mAdapter
     */
    BaseItemDraggableAdapter mAdapter;

    /**
     * 绘制重叠的Bitmap使得可以移除便捷
     */
    private Bitmap mirror;

    /**
     * mirror的位置
     */
    private RectF location;

    /**
     * 移除界的监听器
     */
    private DragListener dragListener;

    /**
     * 拖动的item的Position
     */
    private int selectSubPos;

    /**
     * 是否已出界
     */
    private boolean atOuter;

    /**
     * 当前的状态
     */
    private int glueState = GLUE_STATE_IDEL;

    /**
     * 真正被拖动的View
     */
    private View viewSource;

    /**
     * 模拟的down事件的时间
     */
    private long downTime;
    /**
     * 记录touch时间x与left的偏移
     */
    private float savedOffsetX;
    /**
     * 记录touch时间x与top的偏移
     */
    private float savedOffsetY;

    /**
     * @param context
     * @param parentRecycler
     * @param subRecycler
     */
    public GlueLayout(Context context, RecyclerView parentRecycler, RecyclerView subRecycler) {
        super(context);
        this.parentRecycler = parentRecycler;
        this.subRecycler = subRecycler;
        this.mAdapter = (BaseItemDraggableAdapter) subRecycler.getAdapter();
        ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new SelfEditorDragAndSwipeCallback(mAdapter));
        itemTouchHelper.attachToRecyclerView(subRecycler);
        mAdapter.enableDragItem(itemTouchHelper);
        setBackgroundColor(Color.TRANSPARENT);
//        setBackgroundColor(getResources().getColor(R.color.trans_red));
    }

    public void setDragListener(DragListener dragListener) {
        this.dragListener = dragListener;
    }

    /**
     * 与View粘合
     *
     * @param source
     * @param isParent 是否是parentRecycler
     */
    public void glueTo(View source, boolean isParent) {
        if (mirror != null) {
            if (!mirror.isRecycled()) {
                mirror.recycle();
            }
            mirror = null;
        }
        if (isParent) {
            int tempWidth = viewSource.getWidth();
            int tempHeight = viewSource.getHeight();
            viewSource = source;
            int width = viewSource.getWidth();
            int height = viewSource.getHeight();
            /**
             * sun与parent的ItemView大小不一致
             * 将x、y进行换算
             */
            savedOffsetX *= (float) width / tempWidth;
            savedOffsetY *= (float) height / tempHeight;
            glueState = GLUE_STATE_WITH_PARENT;
//            viewSource.setVisibility(VISIBLE);
            downTime = SystemClock.uptimeMillis();
            /**
             * 模拟down事件，使得item开始拖动
             */
            MotionEvent downEvent = MotionEvent.obtain(downTime, SystemClock.uptimeMillis(),
                    MotionEvent.ACTION_DOWN, viewSource.getLeft() + savedOffsetX, viewSource.getTop() + savedOffsetY, 0);
            parentRecycler.dispatchTouchEvent(downEvent);
            downEvent.recycle();
        } else {
            viewSource = source;
            glueState = GLUE_STATE_WITH_SUB;
        }
        mirror = copyByCanvas(source);
    }


    /**
     * 刷新mirror的位置
     *
     * @param tx
     * @param ty
     */
    private void refresh(float tx, float ty) {
        if (mirror == null) {
            return;
        }
        float left = 0;
        float top = 0;
        if (glueState == GLUE_STATE_WITH_SUB) {
            int[] pos = new int[2];
            viewSource.getLocationOnScreen(pos);
            left = pos[0];
            top = pos[1];
            savedOffsetX = tx - left;
            savedOffsetY = ty - top;
        } else if (glueState == GLUE_STATE_WITH_PARENT) {
            left = tx - savedOffsetX;
            top = ty - savedOffsetY;
        } else if (glueState == GLUE_STATE_OUTER_RELEASE) {
            int[] pos = new int[2];
            viewSource.getLocationOnScreen(pos);
            left = pos[0];
            top = pos[1];
        }
        float right = left + mirror.getWidth();
        float bottom = top + mirror.getHeight();
        if (location == null) {
            location = new RectF();
        }
        location.set(left, top, right, bottom);
        invalidate();
    }


    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        int action = ev.getAction();
        float x = ev.getX();
        float y = ev.getY();
        if (action == MotionEvent.ACTION_UP) {
            if (glueState == GLUE_STATE_WITH_SUB) {
                clearMirror();
            } else if (glueState == GLUE_STATE_WITH_PARENT) {
                /**
                 * 模拟up事件，使得item回到原来位置
                 */
                final int[] loc = new int[2];
                parentRecycler.getLocationOnScreen(loc);
                MotionEvent upEvent = MotionEvent.obtain(downTime, SystemClock.uptimeMillis(),
                        MotionEvent.ACTION_UP, x - loc[0], y - loc[1], 0);
                parentRecycler.dispatchTouchEvent(upEvent);
                upEvent.recycle();
                glueState = GLUE_STATE_OUTER_RELEASE;
                if (viewSource.getAlpha() == 0) {
                    clearMirror();
                } else {
                    RecyclerView.ItemAnimator itemAnimator = parentRecycler.getItemAnimator();
                    long duration = 0;
                    if (itemAnimator == null) {
                        duration = 200L;
                    } else {
                        duration = itemAnimator.getMoveDuration();
                    }
                    parentRecycler.animate()
                            .scaleX(1f)
                            .setDuration(duration)
                            .withEndAction(new Runnable() {
                                @Override
                                public void run() {
                                    clearMirror();
                                }
                            })
                            .setUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                                @Override
                                public void onAnimationUpdate(ValueAnimator animation) {
                                    refresh(0, 0);
                                }
                            }).start();
                }
            }
        } else if (action == MotionEvent.ACTION_MOVE) {
            if (glueState == GLUE_STATE_WITH_PARENT) {
                /**
                 * 模拟move事件，使得item移动
                 */
                final int[] loc = new int[2];
                parentRecycler.getLocationOnScreen(loc);
                MotionEvent moveEvent = MotionEvent.obtain(downTime, SystemClock.uptimeMillis(),
                        MotionEvent.ACTION_MOVE, x - loc[0], y - loc[1], 0);
                parentRecycler.dispatchTouchEvent(moveEvent);
                moveEvent.recycle();
            }
        }
        refresh(ev.getX(), ev.getY());
        return super.dispatchTouchEvent(ev);
    }


    @Override
    protected void dispatchDraw(Canvas canvas) {
        super.dispatchDraw(canvas);
        if (mirror != null && !mirror.isRecycled() && location != null) {
            canvas.drawBitmap(mirror, null, location, null);
        }
    }

    class SelfEditorDragAndSwipeCallback extends ItemDragAndSwipeCallback {

        public SelfEditorDragAndSwipeCallback(BaseItemDraggableAdapter adapter) {
            super(adapter);
        }

        @Override
        public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
            super.onSelectedChanged(viewHolder, actionState);
            if (actionState == ItemTouchHelper.ACTION_STATE_DRAG) {
                selectSubPos = viewHolder.getAdapterPosition();
                glueTo(viewHolder.itemView, false);
            }
        }

        @Override
        public void onMoved(RecyclerView recyclerView, RecyclerView.ViewHolder source, int fromPos, RecyclerView.ViewHolder target, int toPos, int x, int y) {
            super.onMoved(recyclerView, source, fromPos, target, toPos, x, y);
            selectSubPos = toPos;
        }

        @Override
        public int interpolateOutOfBoundsScroll(@NonNull RecyclerView recyclerView, int viewSize, int viewSizeOutOfBounds, int totalSize, long msSinceStartScroll) {
            viewSizeOutOfBounds = viewSizeOutOfBounds > 0 ? viewSizeOutOfBounds - recyclerView.getPaddingBottom() :
                    viewSizeOutOfBounds + recyclerView.getPaddingTop();
            int absOutOfBounds = Math.abs(viewSizeOutOfBounds);
            float outOfBoundsRatio = Math.min(1.0F, 1.0F * (float) absOutOfBounds / (float) viewSize);
            if (outOfBoundsRatio >= 1f && dragListener != null && !atOuter) {
                atOuter = true;
                dragListener.onDragOutOfBounds(selectSubPos, null);
            }
            return super.interpolateOutOfBoundsScroll(recyclerView, viewSize, viewSizeOutOfBounds, totalSize, msSinceStartScroll);
        }
    }

    private void clearMirror() {
        if (glueState == GLUE_STATE_OUTER_RELEASE) {
            glueState = GLUE_STATE_IDEL;
            if (dragListener != null) {
                dragListener.onDragRelease();
            }
            return;
        }
        glueState = GLUE_STATE_IDEL;
        if (mirror != null) {
            mirror.recycle();
        }
        mirror = null;
        location = null;
        invalidate();
    }

    /**
     * 通过canvas复制view的bitmap
     *
     * @param view
     * @return
     */
    private Bitmap copyByCanvas(View view) {
        int width = view.getWidth();
        int height = view.getHeight();
        Bitmap bp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bp);
        view.draw(canvas);
        canvas.save();
        return bp;
    }
}
